package com.example.sources.orm;

import com.example.sources.jdbc.proxy.SimpleDataSource;
import com.example.sources.jdbc.proxy.SqlParameterStatement;
import com.example.sources.util.ClassFileUtil;
import com.example.sources.util.PropertiesUtil;

import javax.persistence.*;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2016/9/22.
 */
public class PersistenceFactory {


    private Map<String, PersistenceField[]> map;

    public PersistenceFactory() {

    }

    public List<Class> getEntityClass() {
        String entityPath = PropertiesUtil.getProperties("entityPath");
        List<Class> classList = new ClassFileUtil().getClassList(entityPath);
        for (int i = 0; i < classList.size(); i++) {
            Class cla = classList.get(i);
            if (cla.getAnnotation(Entity.class) == null) {
                classList.remove(cla);
            }
        }

        return classList;
    }

    public void getEntityMap() {
        map = new HashMap<>();
        List<Class> classList = getEntityClass();
        for (Class c : classList) {
            map.put(c.getSimpleName().toLowerCase(), getEntityField(c));
        }

    }


    public void getTable() {
        getEntityMap();
        SqlParameterStatement sqlParameterStatement = null;
        try {
            sqlParameterStatement = new SqlParameterStatement(new SimpleDataSource().getConnection(),
                    "show tables");
            ResultSet resultSet = sqlParameterStatement.excute();
            List<String> list;
            list = (List<String>) sqlParameterStatement.returnConvert(resultSet, "java.util.List<java.lang.String>");

            int flag = 0;
            for (Class c : getEntityClass()) {
                String entityname = c.getSimpleName().toLowerCase();

                for (String s : list) {
                    if (entityname.equals(s)) {
                        updateTable(c);
                        flag = 1;
                        break;
                    }
                }
 
                if (flag == 0) {
                    System.out.println(creatTable(entityname, map.get(entityname)));
                }

            }

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void updateTable(Class c) {
        String tableName = c.getSimpleName().toLowerCase();
        List<PersistenceField> persistenceFields = getTableField(tableName);

        for (PersistenceField persistenceField : persistenceFields){

        }

        System.out.println(c.getName());

    }

    public List<PersistenceField> getTableField(String tablename) {
        SqlParameterStatement sqlParameterStatement = null;
        List<PersistenceField> list = null;
        try {
            sqlParameterStatement = new SqlParameterStatement(new SimpleDataSource().getConnection(),
                    "desc " + tablename);
            ResultSet resultSet = sqlParameterStatement.excute();

            list = (List<PersistenceField>) sqlParameterStatement.returnConvert(resultSet, "java.util.List<com.example.sources.orm.PersistenceField>");
            for (PersistenceField persistenceField : list) {
                System.out.println(persistenceField.getField());
                System.out.println(persistenceField.getType());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return list;
    }

    private String creatTable(String tablename, PersistenceField[] persistenceFields) {
        String statements = "CREATE TABLE ";
        statements += tablename + "(";
        for (int i = 0; i < persistenceFields.length; i++) {
            if (i != 0) {
                statements += ",";
            }
            statements += persistenceFields[i].getField() + persistenceFields[i].getType() + persistenceFields[i].getNull()
                    + persistenceFields[i].getDefault() + persistenceFields[i].getKey() + persistenceFields[i].getExtra();
        }
        statements += ")";
        return statements;
    }

    private PersistenceField[] getEntityField(Class c) {
        PersistenceField[] persistenceFields = new PersistenceField[c.getDeclaredFields().length];
        int i = 0;
        for (Field field : c.getDeclaredFields()) {

            PersistenceField persistenceField = new PersistenceField();

            persistenceField.setField(field.getName());
            persistenceField.setType(getFieldType(field));
            persistenceField.setDefault(getDefaultValue(field));
            persistenceField.setExtra(getExtra(field));
            persistenceField.setNull(getisNull(field));
            persistenceField.setKey(setPrimary(field));

            persistenceFields[i] = persistenceField;
            i++;

        }
        return persistenceFields;
    }

    private String getExtra(Field field) {
        GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
        if (generatedValue != null) {
            if (generatedValue.strategy() == GenerationType.AUTO)
                return " auto_increment ";
        }
        return "";
    }

    private String setPrimary(Field field) {
        Id id = field.getAnnotation(Id.class);

        if (id != null) {
            return " primary key ";
        } else {
            return "";
        }

    }

    private String getDefaultValue(Field field) {
        Column column = field.getAnnotation(Column.class);
        if (column != null) {
            return column.columnDefinition();
        } else {
            return "";
        }

    }

    private String getisNull(Field field) {
        Column column = field.getAnnotation(Column.class);
        if (column != null) {
            if (column.nullable()) {
                return "";
            } else {
                return " not null ";
            }
        } else {
            return "";
        }
    }

    private String getFieldType(Field field) {
        String type = field.getType().getName();
        if (type.contains("Long")) {
            return " bigint(20) ";
        } else if (type.contains("String")) {

            Column column = field.getAnnotation(Column.class);
            if (column != null) {
                return " varchar" + "(" + column.length() + ") ";
            } else {
                return " varchar(255) ";
            }

        } else if (type.contains("int")) {
            return " int(11) ";
        } else {
            return " varchar(255) ";
        }
    }


}
